package com.ybkj.o2o.zhuanche.common;

/**
 * Created by Administrator on 2016/12/12.
 */

import com.ybkj.o2o.zhuanche.entity.ChartDay;
import com.ybkj.o2o.zhuanche.entity.ChartMonth;
import com.ybkj.o2o.zhuanche.entity.ChartYear;
import com.ybkj.o2o.zhuanche.mapper.ChartDayMapper;
import com.ybkj.o2o.zhuanche.mapper.ChartMonthMapper;
import com.ybkj.o2o.zhuanche.mapper.ChartYearMapper;
import com.ybkj.o2o.zhuanche.mapper.OrderMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class InitChart {

  @Autowired
  private OrderMapper orderMapper;

  @Autowired
  private ChartYearMapper chartYearMapper;

  @Autowired
  private ChartMonthMapper chartMonthMapper;

  @Autowired
  private ChartDayMapper chartDayMapper;

  /**
   * 初始化统计数据.
   */
  @Transactional(rollbackFor = Exception.class)
  public void migration(String appKey) {
    this.setEmpty(appKey);
    Calendar cal = Calendar.getInstance();
    int year = cal.get(Calendar.YEAR);
    cal.set(Calendar.MONTH, 0);
    cal.set(Calendar.DATE, 1);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    Date start = cal.getTime();
    cal.set(Calendar.MONTH, 11);
    cal.set(Calendar.DAY_OF_MONTH, 31);
    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 59);
    cal.set(Calendar.SECOND, 59);
    Date end = cal.getTime();
    List<ChartYear> cys = chartYearMapper.selectAllByYear(year,appKey);
    if (CollectionUtils.isEmpty(cys)) {
      initChartYear(start, end, year,appKey);
      initChartMonth(year,appKey);
      initChartDay(year,appKey);
      initChartHour(year,appKey);
    }
    List<ChartYear> cyss = chartYearMapper.selectAllByYear(year - 1,appKey);
    if (CollectionUtils.isEmpty(cyss)) {
      cal.set(year - 1, 0, 1, 0, 0, 0);
      start = cal.getTime();
      cal.set(Calendar.MONTH, 11);
      cal.set(Calendar.DAY_OF_MONTH, 31);
      cal.set(Calendar.HOUR_OF_DAY, 23);
      cal.set(Calendar.MINUTE, 59);
      cal.set(Calendar.SECOND, 59);
      end = cal.getTime();
      initChartYear(start, end, year - 1,appKey);
      initChartMonth(year - 1,appKey);
      initChartDay(year - 1,appKey);
      initChartHour(year - 1,appKey);
    }

  }

  private void initChartYear(Date start, Date end, int year,String appKey) {
    List<Map<String, Object>> finish = orderMapper.chartFinishDate(start, end,appKey);
    List<Map<String, Object>> cancel = orderMapper.chartCancel(start, end,appKey);
    for (Map<String, Object> map : finish) {
      ChartYear cy = new ChartYear();
      cy.setAppKey((String) map.get("appKey"));
      cy.setCompanyId(Long.parseLong(map.get("companyId").toString()));
      cy.setTotalSuccessNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
      cy.setTotalPrice(
          new BigDecimal(Double.parseDouble(map.getOrDefault("money", 0.0).toString())));
      cy.setTotalCancelNum(0L);
      cy.setYear(year);
      chartYearMapper.insertRecord(cy);
    }
    for (Map<String, Object> map : cancel) {
      ChartYear cy = chartYearMapper.selectByYearAndCompany(
          year, Long.parseLong(map.get("companyId").toString()), (String) map.get("appKey"));
      if (cy != null) {
        cy.setTotalCancelNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
        chartYearMapper.updateByPrimaryKey(cy);
      } else {
        cy = new ChartYear();
        cy.setAppKey((String) map.get("appKey"));
        cy.setCompanyId(Long.parseLong(map.get("companyId").toString()));
        cy.setTotalSuccessNum(0L);
        cy.setTotalPrice(BigDecimal.ZERO);
        cy.setTotalCancelNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
        cy.setYear(year);
        chartYearMapper.insertRecord(cy);
      }
    }


  }

  private void initChartMonth(int year,String appKey) {
    Calendar cal = Calendar.getInstance();
    for (int i = 0; i < 12; i++) {
      cal.clear();
      cal.set(year, i, 1, 0, 0, 0);
      Date start = cal.getTime();
      cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
      cal.set(Calendar.HOUR_OF_DAY, 23);
      cal.set(Calendar.MINUTE, 59);
      cal.set(Calendar.SECOND, 59);
      Date end = cal.getTime();
      List<Map<String, Object>> finish = orderMapper.chartFinishDate(start, end,appKey);
      List<Map<String, Object>> cancel = orderMapper.chartCancel(start, end,appKey);
      for (Map<String, Object> map : finish) {
        ChartYear chartYear = chartYearMapper.selectByYearAndCompany(
            year, Long.parseLong(map.get("companyId").toString()), (String) map.get("appKey"));
        if (chartYear == null) {
          continue;
        } 
        ChartMonth cm = new ChartMonth();
        cm.setYearId(chartYear.getId());
        cm.setMonth(i);
        cm.setAppKey((String) map.get("appKey"));
        cm.setTotalSuccessNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
        cm.setTotalPrice(new BigDecimal((double) map.getOrDefault("money", 0.0)));
        cm.setTotalCancelNum(0L);
        chartMonthMapper.insertRecord(cm);
      }
      for (Map<String, Object> map : cancel) {
        ChartYear chartYear = chartYearMapper.selectByYearAndCompany(
            year, Long.parseLong(map.get("companyId").toString()), (String) map.get("appKey"));
        if (chartYear == null) {
          continue;
        } 
        ChartMonth cm = chartMonthMapper.selectByYearAndMonth(
            chartYear.getId(), i, (String) map.get("appKey"));
        if (cm != null) {
          cm.setTotalCancelNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
          chartMonthMapper.updateByPrimaryKey(cm);
        } else {
          cm = new ChartMonth();
          cm.setYearId(chartYear.getId());
          cm.setMonth(i);
          cm.setAppKey((String) map.get("appKey"));
          cm.setTotalSuccessNum(0L);
          cm.setTotalPrice(BigDecimal.ZERO);
          cm.setTotalCancelNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
          chartMonthMapper.insertRecord(cm);
        }
      }

    }

  }


  private void initChartDay(int year,String appKey) {
    List<ChartYear> list = chartYearMapper.selectAllByYear(year,appKey);
    Calendar cal = Calendar.getInstance();
    for (ChartYear cy : list) {
      List<ChartMonth> cms = chartMonthMapper.queryMonthByYear(cy.getId(), cy.getAppKey());
      for (ChartMonth cm : cms) {
        cal.clear();
        cal.set(year, cm.getMonth(), 1, 0, 0, 0);
        int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        for (int day = 1; day <= maxDay; day++) {
          cal.set(Calendar.DAY_OF_MONTH, day);
          cal.set(Calendar.HOUR_OF_DAY, 0);
          cal.set(Calendar.MINUTE, 0);
          cal.set(Calendar.SECOND, 0);
          Date start = cal.getTime();
          cal.set(Calendar.DAY_OF_MONTH, day);
          cal.set(Calendar.HOUR_OF_DAY, 23);
          cal.set(Calendar.MINUTE, 59);
          cal.set(Calendar.SECOND, 59);
          Date end = cal.getTime();
          List<Map<String, Object>> finish = orderMapper.chartFinishDate(start, end,appKey);
          List<Map<String, Object>> cancel = orderMapper.chartCancel(start, end,appKey);
          for (Map<String, Object> map : finish) {
            if (cm.getAppKey().equals((String) map.get("appKey")) 
                && cy.getCompanyId().equals((Long) map.get("companyId"))) {
              ChartDay cd = new ChartDay();
              cd.setMonthId(cm.getId());
              cd.setDay(day);
              cd.setAppKey((String) map.get("appKey"));
              cd.setTotalSuccessNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
              cd.setTotalPrice(new BigDecimal((double) map.getOrDefault("money", 0.0)));
              cd.setTotalCancelNum(0L);
              chartDayMapper.insertRecord(cd);
            }
          }

          for (Map<String, Object> map : cancel) {
            if (cm.getAppKey().equals((String) map.get("appKey")) 
                && cy.getCompanyId().equals((Long) map.get("companyId"))) {
              ChartDay cd = chartDayMapper.selectByMonthAndDay(cm.getId(), day, cm.getAppKey());
              if (cd != null) {
                cd.setTotalCancelNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
                chartDayMapper.updateByPrimaryKey(cd);
              } else {
                cd = new ChartDay();
                cd.setMonthId(cm.getId());
                cd.setDay(day);
                cd.setAppKey((String) map.get("appKey"));
                cd.setTotalSuccessNum(0L);
                cd.setTotalPrice(BigDecimal.ZERO);
                cd.setTotalCancelNum(Long.parseLong(map.getOrDefault("total", 0L).toString()));
                chartDayMapper.insertRecord(cd);
              }
            }

          }

        }
      }

    }

  }

  private void initChartHour(int year,String appKey) {
    Calendar cal = Calendar.getInstance();
    List<ChartYear> list = chartYearMapper.selectAllByYear(year,appKey);
    for (ChartYear cy : list) {
      List<ChartMonth> cms = chartMonthMapper.queryMonthByYear(cy.getId(), cy.getAppKey());
      for (ChartMonth cm : cms) {
        List<ChartDay> cds = chartDayMapper.queryDayByMonth(cm.getId(), cm.getAppKey());

        for (ChartDay cd : cds) {
          for (int i = 0; i < 24; i++) {
            cal.clear();
            cal.set(year, cm.getMonth(), cd.getDay(), i, 0, 0);
            Date start = cal.getTime();
            cal.set(year, cm.getMonth(), cd.getDay(), i, 59, 59);
            Date end = cal.getTime();
            List<Map<String, Object>> finish = orderMapper.chartFinishDate(start, end,appKey);
            List<Map<String, Object>> cancel = orderMapper.chartCancel(start, end,appKey);

            for (Map<String, Object> map : finish) {
              if (cy.getCompanyId().equals((Long) map.get("companyId")) 
                  && cy.getAppKey().equals((String) map.get("appKey"))) {
                Class<ChartDay> clazz = ChartDay.class;
                Method getHourSuccess = 
                    ReflectionUtils.findMethod(clazz, "getHour" + i + "SuccessNum");
                Method setHourSuccess = 
                    ReflectionUtils.findMethod(clazz, "setHour" + i + "SuccessNum", long.class);

                Method getMethodPrice = 
                    ReflectionUtils.findMethod(clazz, "getHour" + i + "TotalPrice");
                Method setMethodPrice = ReflectionUtils.findMethod(
                    clazz, "setHour" + i + "TotalPrice", BigDecimal.class);

                long num = (Long) ReflectionUtils.invokeMethod(getHourSuccess, cd);
                
                ReflectionUtils.invokeMethod(
                    setHourSuccess, cd, (long) map.getOrDefault("total", 0L) + num);

                BigDecimal price = (BigDecimal) ReflectionUtils.invokeMethod(getMethodPrice, cd);
                ReflectionUtils.invokeMethod(setMethodPrice, cd, 
                    new BigDecimal((double) map.getOrDefault("money", 0.0)).add(price));

                chartDayMapper.updateByPrimaryKey(cd);
              }
            }
            for (Map<String, Object> map : cancel) {
              if (cy.getCompanyId().equals((Long) map.get("companyId")) 
                  && cy.getAppKey().equals((String) map.get("appKey"))) {
                Class<ChartDay> clazz = ChartDay.class;
                Method getMethod = ReflectionUtils.findMethod(clazz, "getHour" + i + "CancelNum");
                Method setMethod = ReflectionUtils.findMethod(
                    clazz, "setHour" + i + "CancelNum", long.class);
                long num = (Long) ReflectionUtils.invokeMethod(getMethod, cd);
                ReflectionUtils.invokeMethod(
                    setMethod, cd, num + Long.parseLong(map.getOrDefault("total", 0L).toString()));
                chartDayMapper.updateByPrimaryKey(cd);
              }
            }
          }
        }
      }
    }

  }

  private void setEmpty(String appKey) {
    chartYearMapper.setEmpty(appKey);
    chartMonthMapper.setEmpty(appKey);
    chartDayMapper.setEmpty(appKey);
  }

}
